package com.gis3c.sys.service.impl;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import com.gis3c.common.exception.BusinessException;
import com.gis3c.sys.entry.po.Token;
import com.gis3c.sys.entry.po.User;
import com.gis3c.sys.entry.vo.UserModel;
import com.gis3c.sys.dao.UserDao;
import com.gis3c.sys.service.UserService;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.gis3c.sys.common.PasswordHelper;
import com.gis3c.sys.security.shiro.token.HmacSHA256Utils;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("userService")
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {
    @Autowired private Mapper baseMapper;
    @Resource private UserDao userDao;
    @Resource private PasswordHelper passwordHelper;

    @Override
    @Transactional(propagation= Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
    public UserModel createUser(UserModel userModel) {
        User user = baseMapper.map(userModel,User.class);
        user.setId(UUID.randomUUID().toString());
        passwordHelper.encryptPassword(user);

        userDao.correlationOrg(user.getId(),userModel.getOrgId());
        return baseMapper.map(userDao.createUser(user),UserModel.class);
    }

    @Override
    public int deleteUsers(String[] userIds){
        return userDao.deleteUsers(userIds);
    }

    @Override
    public void changePassword(String userId, String newPassword) {
        User user = userDao.findOne(userId);
        user.setPassword(newPassword);
        passwordHelper.encryptPassword(user);
        userDao.changePassword(userId,user.getPassword(),user.getSalt());
    }



    @Override
    public User findByUsername(String username){
        return userDao.findByUsername(username);
    }
    @Override
    public UserModel findUserByUsername(String username) {
        return baseMapper.map(userDao.findByUsername(username),UserModel.class);
    }
    @Override
    public UserModel findByUserId(String userId){
        return baseMapper.map(userDao.findOne(userId),UserModel.class);
    }

    @Override
    public int userCount(String username){
        return userDao.userCount(username);
    }

    @Override
    public List<UserModel> allUsers(){
        List<UserModel> userModelList = new ArrayList<>();
        List<User> queryResult =  userDao.allUsers();
        queryResult.forEach(user -> userModelList.add(baseMapper.map(user,UserModel.class)));
        return userModelList;
    }

    @Override
    public List<UserModel> allUsersByPage(int pagesize,int currentpage){
        List<UserModel> userModelList = new ArrayList<>();
        List<User> queryResult =  userDao.allUsersByPage(pagesize,currentpage);
        queryResult.forEach(user -> userModelList.add(baseMapper.map(user,UserModel.class)));
        return userModelList;
    }


    @Override
    public Integer allUsersCount(){
        return userDao.allUsersCount();
    }

    @Override
    public Set<String> findPermissions(String username) {
        Set<String> permissions = new HashSet<>();
        List<String> permissionList = userDao.findPermissions(username);
        if(permissionList != null && permissionList.size() > 0){
            for(String permission : permissionList){
                permissions.add(permission);
            }
        }
        return permissions;
    }

    @Override
    public Token findTokenByUserId(String userId) {
        return userDao.findTokenByUserId(userId);
    }

    @Override
    public void correlationOrg(String userId, String orgId){
        userDao.correlationOrg(userId, orgId);
    }

    @Override
    public void uncorrelationOrg(String userId){
        userDao.uncorrelationOrg(userId);
    }

    @Override
    public List<UserModel> findUsersByOrgId(String orgId){
        List<UserModel> userModelList = new ArrayList<>();
        List<User> queryResult =  userDao.findUsersByOrgId(orgId);
        queryResult.forEach(user -> userModelList.add(baseMapper.map(user,UserModel.class)));
        return userModelList;
    }

    @Override
    public List<UserModel> findUsersByOrgId(String orgId, int pagesize, int currentpage) {
        List<UserModel> userModelList = new ArrayList<>();
        List<User> queryResult =  userDao.findUsersByOrgId(orgId)
                .stream().skip(pagesize * (currentpage-1)).limit(pagesize)
                .collect(Collectors.toList());
        queryResult.forEach(user -> userModelList.add(baseMapper.map(user,UserModel.class)));
        return userModelList;
    }

    @Override
    public Integer usersCountByOrgId(String orgId) {
        return userDao.findUsersByOrgId(orgId).size();
    }


    @Override
    public List<Map<String,Object>> getUserWithToken(String userId) {
        return userDao.getUserWithToken(userId);
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
    public int updateToken(Token token) {
        if (userDao.exitToken(token.getUserId())==true) {
            return userDao.updateToken(token);
        }else {
            return userDao.createToken(token);
        }
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
    public boolean deleteUserWithToken(String userId) {
        int row=0;
        row+= userDao.deleteUser(userId);
        row+= userDao.deleteToken(userId);
        return row>0?true:false;
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
    public int deleteToken(String userId) {
        return userDao.deleteToken(userId);
    }

    @Override
    public String getUserNameByToken(String token){
        return  userDao.getUserNameByToken(token);
    }

    @Override
    public String createDigest(String secretKey,String userName){
        String digest = null;
        if(secretKey != null && userName != null){
            try{
                digest = HmacSHA256Utils.digest(secretKey, userName);
            }catch(Exception e){
                throw new BusinessException("token生成失败",e);
            }
        }
        return digest;
    }

    @Override
    public Token createToken(String userId) {
        Token resultToken = null;
        if(userId == null || "".equals(userId)){
            throw new BusinessException("用户名不能为空");
        }

        /**
         * 通过用户名获取用户id
         */
        User queryUser = userDao.findOne(userId);
        /**
         * 利用用户名生成token
         */
        String secretKey = passwordHelper.randomNumber();
        try {
            resultToken = new Token(queryUser.getId()
                    ,secretKey
                    ,HmacSHA256Utils.digest(secretKey, userId)
                    ,new Date());
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException |InvalidKeyException  e) {
            throw new BusinessException("Token生成失败",e);
        }

        return resultToken;
    }

    @Override
    public Token createToken(String userId, String secretKey){
        Token resultToken = null;
        if(userId == null || "".equals(userId)
                || secretKey == null || "".equals(secretKey)){
            throw new BusinessException("token参数设置出错");
        }
        User queryUser = userDao.findOne(userId);
        if(queryUser == null){
            throw new BusinessException("token参数设置出错");
        }


        try {
            resultToken = new Token(userId,secretKey
                    ,HmacSHA256Utils.digest(secretKey, queryUser.getUsername())
                    ,new Date());
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException |InvalidKeyException  e) {
            throw new BusinessException("Token生成失败",e);
        }
        return resultToken;
    }

    @Override
    public String findsecretByUserName(String userName){
        return userDao.findsecretByUserName(userName == null ?"":userName);
    }

    @Override
    public String getTokenByUserName(String userName){
        if(userName == null || "".equals(userName)){
            throw new BusinessException("userName不能为空");
        }
        return userDao.getTokenByUserName(userName);
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
    public void updateTokeTime(String tokenStr){
        userDao.updateTokeTime(tokenStr);
    }
}

